﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace VemTransporte.Models.Basica
{
    public class Distance
    {
        const double PIx = 3.141592653589793;
        const double RADIO = 6378.16;

        /// <summary>
        /// Convert degrees to Radians
        /// </summary>
        /// <param name="x">Degrees</param>
        /// <returns>The equivalent in radians</returns>
        public static double Radians(double x)
        {
            return x * PIx / 180;
        }

        /// <summary>
        /// Calculate the distance between two places.
        /// </summary>
        /// <param name="lon1"></param>
        /// <param name="lat1"></param>
        /// <param name="lon2"></param>
        /// <param name="lat2"></param>
        /// <returns></returns>
        public static double DistanceBetweenPlaces(
            double lon1,
            double lat1,
            double lon2,
            double lat2)
        {
            double dlon = lon2 - lon1;
            double dlat = lat2 - lat1;

            double a = (Math.Sin(dlat / 2) * Math.Sin(dlat / 2)) + Math.Cos(lat1) * Math.Cos(lat2) * (Math.Sin(dlon / 2) * Math.Sin(dlon / 2));
            double angle = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
            return angle * RADIO;
        }


        /// <summary>
        /// Calculate the distance between two points.
        /// </summary>
        /// <param name="lon1"></param>
        /// <param name="lat1"></param>
        /// <param name="lon2"></param>
        /// <param name="lat2"></param>
        /// <returns>Metros</returns>
        public static double GetDistanceBetweenPoints(double lat1, double long1, double lat2, double long2)
        {
            double distance = 0;

            double dLat = (lat2 - lat1) / 180 * Math.PI;
            double dLong = (long2 - long1) / 180 * Math.PI;

            double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2)
                        + Math.Cos(lat2) * Math.Sin(dLong / 2) * Math.Sin(dLong / 2);
            double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));

            //Calculate radius of earth
            // For this you can assume any of the two points.
            double radiusE = 6378135; // Equatorial radius, in metres
            double radiusP = 6356750; // Polar Radius

            //Numerator part of function
            double nr = Math.Pow(radiusE * radiusP * Math.Cos(lat1 / 180 * Math.PI), 2);
            //Denominator part of the function
            double dr = Math.Pow(radiusE * Math.Cos(lat1 / 180 * Math.PI), 2)
                            + Math.Pow(radiusP * Math.Sin(lat1 / 180 * Math.PI), 2);
            double radius = Math.Sqrt(nr / dr);

            //Calaculate distance in metres.
            distance = radius * c;
            return distance;
        }

        private static string[] cnUnidadeGenero = { "uma", "duas", "um", "dois" };
        private static string[] cnUnidade = { "três", "quatro", "cinco", "seis", "sete", "oito", "nove" };
        private static string[] cnDezena10 =  {"onze", "doze", "treze", "quatorze", "quinze", "dezesseis", 
                                              "dezessete", "dezoito", "dezenove"};
        private static string[] cnDezena =  {"dez", "vinte", "trinta", "quarenta", "cinqüenta", "sessenta", 
                                              "setanta", "oitenta", "noventa"};

        // monta apenas números decimais (até 99)
        private static string DecimalExtenso(int Num, bool Masculino)
        {
            string retorno = null;
            int Unidade;
            int Dezena;

            if (Num > 0)
            {
                Unidade = Num % 10;
                Dezena = Num / 10;
                if (Dezena == 0)
                {
                    if (Unidade <= 2)  // Os números 1 e 2 podem variar em gênero
                        retorno = cnUnidadeGenero[Unidade + (Convert.ToByte(Masculino))];
                    else
                        retorno = cnUnidade[Unidade];
                }
                else
                    if (Unidade == 0)
                        retorno = cnDezena[Dezena];
                    else
                        if (Dezena == 1)
                            retorno = cnDezena10[Num];
                        else
                            if (Dezena <= 9)
                                if (Unidade <= 2)  // Os números 1 e 2 podem variar em gênero
                                    retorno = cnDezena[Dezena] + " e " + cnUnidadeGenero[Unidade + (Convert.ToByte(Masculino))];
                                else
                                    retorno = cnDezena[Dezena] + " e " + cnUnidade[Unidade];
            }
            else
                retorno = "zero";
            return retorno;
        }

        // Monta a hora por extenso.
        // Pode receber um campo composto por data e hora, sem problemas
        public static string HoraPorExtenso(TimeSpan hora)
        {
            string retorno = null;

            int Hora = (int)(hora.Hours);
            int Minuto = (int)hora.Minutes;
            int Segundos = (int)hora.Seconds;

            if (Minuto == 60)
            {
                Hora++;
                Minuto = 0;
            }

            if (Hora > 0)
            {
                retorno = DecimalExtenso(Hora, false) + " hora";
                if (Hora > 1)
                    retorno = retorno + "s";
            }
            if ((Minuto > 0) && (Hora > 0))
            {
                retorno = retorno + " e " + DecimalExtenso(Minuto, true) + " minuto";
                if (Minuto > 1)
                    retorno = retorno + "s";
            }
            else if (Minuto > 0)
            {
                retorno = DecimalExtenso(Minuto, true) + " minuto";
                if (Minuto > 1)
                    retorno = retorno + "s";
            }

            if (Segundos > 0)
            {
                if (Minuto > 0)
                    retorno += " e " + Segundos + " segundo";
                else
                    retorno += Segundos + " segundo";
                if (Segundos > 1)
                    retorno += "s";
            }
            return retorno;
        }
    }
}